package com.yupi.springbootinit.utils;

import okhttp3.*;
import java.io.IOException;
import java.time.Duration;
import java.util.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.node.*;

/**
 * ChatAiUtils: SiliconFlow 对话 API 的 Java 工具类
 * 支持：
 *  - OpenAI 风格: /v1/chat/completions  -> 提取 choices[0].message.content
 *  - Anthropic 风格: /v1/claude-messages -> 提取 content[0].text
 * 
 * 使用示例：
 * 
 * 1. 基本使用：
 * ```
 * List<ChatAiUtils.Message> messages = Arrays.asList(
 *     ChatAiUtils.Message.system("你是一个 helpful assistant"),
 *     ChatAiUtils.Message.user("你好，介绍一下你自己")
 * );
 * 
 * String response = ChatAiUtils.chatOpenAI(
 *     "your-api-key",
 *     "Qwen/Qwen2-7B-Instruct",
 *     messages,
 *     1000,
 *     0.7
 * );
 * ```
 * 
 * 2. 数据分析专家角色使用：
 * ```
 * List<ChatAiUtils.Message> messages = Arrays.asList(
 *     ChatAiUtils.Message.system("你是一个数据分析师和前端开发专家，接下来我会按照以下固定格式给你提供内容：\n" +
 *         "分析需求：\n" +
 *         "{数据分析的需求或者目标}\n" +
 *         "原始数据：\n" +
 *         "{csv格式的原始数据，用,作为分隔符}\n" +
 *         "请根据这两部分内容，按照以下指定格式生成内容（此外不要输出任何多余的开头、结尾、注释）\n" +
 *         "【【【【【\n" +
 *         "{前端 Echarts V5 的 option 配置对象js代码，合理地将数据进行可视化，不要生成任何多余\n" +
 *         "【【【【【\n" +
 *         "{明确的数据分析结论、越详细越好，不要生成多余的注释"),
 *     ChatAiUtils.Message.user("分析需求：分析网站用户访问趋势\n" +
 *         "原始数据：\n" +
 *         "日期,访问量\n" +
 *         "2023-10-01,1200\n" +
 *         "2023-10-02,1500\n" +
 *         "2023-10-03,1800")
 * );
 * 
 * String response = ChatAiUtils.chatOpenAI(
 *     "your-api-key",
 *     "Qwen/Qwen3-8B",
 *     messages,
 *     1500,
 *     0.3
 * );
 * ```
 * 
 * 3. 多轮对话：
 * ```
 * // 第一轮对话
 * List<ChatAiUtils.Message> messages1 = Arrays.asList(
 *     ChatAiUtils.Message.system("你是一个编程助手，专门帮助解决 Java 编程问题。"),
 *     ChatAiUtils.Message.user("什么是 Java 中的多态？")
 * );
 * 
 * String response1 = ChatAiUtils.chatOpenAI(
 *     "your-api-key",
 *     "Qwen/Qwen2-7B-Instruct",
 *     messages1,
 *     600,
 *     0.7
 * );
 * 
 * // 第二轮对话 - 继续之前的对话
 * List<ChatAiUtils.Message> messages2 = Arrays.asList(
 *     ChatAiUtils.Message.system("你是一个编程助手，专门帮助解决 Java 编程问题。"),
 *     ChatAiUtils.Message.user("什么是 Java 中的多态？"),
 *     ChatAiUtils.Message.assistant(response1), // 添加上一轮的助手回复
 *     ChatAiUtils.Message.user("能给一个具体的代码示例吗？")
 * );
 * 
 * String response2 = ChatAiUtils.chatOpenAI(
 *     "your-api-key",
 *     "Qwen/Qwen2-7B-Instruct",
 *     messages2,
 *     600,
 *     0.7
 * );
 * ```
 */
public final class ChatAiUtils {

    private static final String BASE_URL = "https://api.siliconflow.cn";
    private static final String OPENAI_CHAT_PATH = "/v1/chat/completions";
    private static final String ANTHROPIC_CHAT_PATH = "/v1/claude-messages";

    private static final MediaType JSON = MediaType.get("application/json");
    // 增加超时时间，避免因响应时间过长导致超时
    private static final OkHttpClient CLIENT = new OkHttpClient.Builder()
            .connectTimeout(Duration.ofSeconds(60))   // 连接超时60秒
            .readTimeout(Duration.ofSeconds(180))     // 读取超时3分钟
            .writeTimeout(Duration.ofSeconds(60))     // 写入超时1分钟
            .build();

    private static final ObjectMapper MAPPER = new ObjectMapper();

    private ChatAiUtils() {}

    /**
     * OpenAI 风格对话调用。
     * 返回第一条回答文本（choices[0].message.content）。
     */
    public static String chatOpenAI(
            String apiKey,
            String model,
            List<Message> messages,
            Integer maxTokens,
            Double temperature
    ) throws IOException {

        Objects.requireNonNull(apiKey, "apiKey is required");
        Objects.requireNonNull(model, "model is required");
        Objects.requireNonNull(messages, "messages is required");
        if (messages.isEmpty()) throw new IllegalArgumentException("messages cannot be empty");

        ObjectNode root = MAPPER.createObjectNode();
        root.put("model", model);

        ArrayNode msgs = MAPPER.createArrayNode();
        for (Message m : messages) {
            ObjectNode item = MAPPER.createObjectNode();
            item.put("role", m.role);
            item.put("content", m.content);
            msgs.add(item);
        }
        root.set("messages", msgs);

        if (maxTokens != null) root.put("max_tokens", maxTokens);
        if (temperature != null) root.put("temperature", temperature);

        Request request = new Request.Builder()
                .url(BASE_URL + OPENAI_CHAT_PATH)
                .addHeader("Authorization", "Bearer " + apiKey)
                .addHeader("Content-Type", "application/json")
                .post(RequestBody.create(MAPPER.writeValueAsBytes(root), JSON))
                .build();

        try (Response resp = CLIENT.newCall(request).execute()) {
            String respBody = resp.body() == null ? "" : resp.body().string();
            if (!resp.isSuccessful()) {
                throw new IOException("OpenAI-style request failed: HTTP " + resp.code() + " - " + respBody);
            }

            JsonNode json = MAPPER.readTree(respBody);
            JsonNode choices = json.get("choices");
            if (choices != null && choices.isArray() && choices.size() > 0) {
                JsonNode message = choices.get(0).get("message");
                if (message != null) {
                    JsonNode content = message.get("content");
                    if (content != null && !content.isNull()) {
                        return content.asText();
                    }
                }
            }
            // 兜底：若结构变化，返回原始 JSON，便于排查
            return respBody;
        }
    }

    /**
     * Anthropic 风格对话调用。
     * 返回第一段文本（content[0].text）。
     */
    public static String chatAnthropic(
            String apiKey,
            String model,
            List<Message> messages,
            Integer maxTokens,  // 统一参数名
            Double temperature
    ) throws IOException {

        Objects.requireNonNull(apiKey, "apiKey is required");
        Objects.requireNonNull(model, "model is required");
        Objects.requireNonNull(messages, "messages is required");
        if (messages.isEmpty()) throw new IllegalArgumentException("messages cannot be empty");

        ObjectNode root = MAPPER.createObjectNode();
        root.put("model", model);

        ArrayNode msgs = MAPPER.createArrayNode();
        for (Message m : messages) {
            ObjectNode item = MAPPER.createObjectNode();
            item.put("role", m.role);
            ArrayNode contentArr = MAPPER.createArrayNode();
            ObjectNode textPart = MAPPER.createObjectNode();
            textPart.put("type", "text");
            textPart.put("text", m.content);
            contentArr.add(textPart);
            item.set("content", contentArr);
            msgs.add(item);
        }
        root.set("messages", msgs);

        // 使用统一的参数名
        if (maxTokens != null) root.put("max_tokens", maxTokens);
        if (temperature != null) root.put("temperature", temperature);

        Request request = new Request.Builder()
                .url(BASE_URL + ANTHROPIC_CHAT_PATH)
                .addHeader("Authorization", "Bearer " + apiKey)
                .addHeader("Content-Type", "application/json")
                .post(RequestBody.create(MAPPER.writeValueAsBytes(root), JSON))
                .build();

        try (Response resp = CLIENT.newCall(request).execute()) {
            String respBody = resp.body() == null ? "" : resp.body().string();
            if (!resp.isSuccessful()) {
                throw new IOException("Anthropic-style request failed: HTTP " + resp.code() + " - " + respBody);
            }

            JsonNode json = MAPPER.readTree(respBody);
            JsonNode content = json.get("content");
            if (content != null && content.isArray() && content.size() > 0) {
                JsonNode first = content.get(0);
                JsonNode text = first.get("text");
                if (text != null && !text.isNull()) {
                    return text.asText();
                }
            }
            // 兜底：若结构变化，返回原始 JSON，便于排查
            return respBody;
        }
    }

    /**
     * 简单的消息对象：role 可用 "user" / "assistant" / "system"，content 为纯文本。
     */
    public static class Message {
        public final String role;
        public final String content;

        public Message(String role, String content) {
            this.role = Objects.requireNonNull(role, "role is required");
            this.content = Objects.requireNonNull(content, "content is required");
        }

        public static Message of(String role, String content) { return new Message(role, content); }
        public static Message user(String content) { return new Message("user", content); }
        public static Message system(String content) { return new Message("system", content); }
        public static Message assistant(String content) { return new Message("assistant", content); }
    }
}